package compiler;

/*Diego Lima de Freitas RA: 317632
 *Yuri Souza Padua RA: 317420

Gramática - NTSA

Program ::= GlobalVarList ProcList
GlobalVarList ::= [ VarDec { VarDec } ]
ProcList ::= ProcDec { ProcDec }
ProcDec ::= "proc" [ Type ] Id "(" [ ParamList ] ")"
[ VarDec { VarDec } ] ProcBody
ParamList ::= Type Id {"," Type Id }
ProcBody ::= "begin" { Command } "end"
CompositeCommand ::= "begin" { Command } "end"
Command ::= PrintCommand | AssignmentCommand | WhileCommand | ForCommand | IfCommand
| CompositeCommand | ReturnCommand | ProcCall
VarDec ::= Type Id { "," Id } ";"
Type ::= "integer" | "boolean"
AssignmentCommand ::= Id "=" OrExpr ";"
PrintCommand ::= "print" OrExpr ";"
WhileCommand ::= "while" OrExpr "do" Command
ForCommand ::= "for" Id "=" OrExpr "to" OrExpr "do" Command
IfCommand ::= "if" OrExpr "then" Command [ "else" Command ]
ReturnCommand ::= "return" OrExpr ";"
ProcCall ::= Id "(" [ OrExpr { "," OrExpr } ] ")"
OrExpr ::= AndExpr [ "or" AndExpr ]
AndExpr ::= RelExpr [ "and" RelExpr ]
RelExpr ::= AddExpr [ RelOp AddExpr ]
AddExpr ::= MultExpr { AddOp MultExpr }
MultExpr ::= SimpleExpr { MultOp SimpleExpr }
SimpleExpr ::= Number | "true" | "false" | ’(’ OrExpr ’)’ |
"not" SimpleExpr | AddOp SimpleExpr | Id | getInteger | ProcCall
RelOp ::= ’<’ | ’<=’ | ’>’ | ’>=’| ’==’ | ’<>’
AddOp ::= ’+’| ’-’
MultOp ::= ’*’ | ’/’ | ’%’
Number ::= Digit { Digit }
Digit ::= ’0’| ’1’ | ... | ’9’
FuncCall ::= Id "(" [ OrExpr { "," OrExpr } ] ")"

   
*/

import AST.*;
import Lexer.Lexer;
import Lexer.Symbol;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Random;



public class Compiler {

    
    private SymbolTable symbolTable;
    private Lexer lexer;
    private CompilerError error;
    
      // ponteiro para a função atual
    private Procedure currentFunction;
    private Procedure currentProcedure;
    
    
     
    public Program compile( char []input, PrintWriter outError ) {
        
        symbolTable = new SymbolTable();
        error = new CompilerError( lexer, new PrintWriter(outError) );
        lexer = new Lexer(input, error);
        error.setLexer(lexer);
        
        lexer.nextToken();
        
        Program p = null;
        try {
          p = program();
        } catch ( Exception e ) {
              
            e.printStackTrace();
        }
          return p;
        }
  
    private Program program() {
        // Program ::= GlobalList ProcFunc { ProcFunc }


        GlobalVarList globalvarList = null;

        while (lexer.token == Symbol.INTEGER || lexer.token == Symbol.BOOLEAN) {
            globalvarList = globalVar();
        }

        //Lista de procedimentos
        ArrayList<Subroutine> procfuncList = new ArrayList<Subroutine>();

        while (lexer.token == Symbol.PROCEDURE) {
            procfuncList.add(procDec());

        }

        if (currentProcedure != null) {
            if (currentProcedure.getParamList() != null) {
                error.signal("o ultimo procedimento nao deve ter parametros");
            }
        } else {
            error.signal("o ultimo procedimento nao deve ter tipo de retorno");
        }

        currentProcedure.setNameMain();

        Program program = new Program(procfuncList, globalvarList);
        if (lexer.token != Symbol.EOF) {
            error.signal("EOF esperado");
        }

        return program;
    }

 
    private GlobalVarList globalVar() {
        //GlobalVarList ::= [ VarDec { VarDec } ]
        GlobalVarList globalVarList = new GlobalVarList();

        while (lexer.token == Symbol.INTEGER || lexer.token == Symbol.BOOLEAN) {
            boolean isBoolean = false;
            VarDec v;

            // flag de identificacao de tipo de variavel
            if (lexer.token == Symbol.BOOLEAN) {
                isBoolean = true;
            }

            lexer.nextToken();

            //estamos no nome da variavel
            while (true) {
                if (lexer.token != Symbol.IDENT) {
                    error.signal("Esperado Identificador");
                    // name of the identifier
                }
                String name = (String) lexer.getStringValue();
                lexer.nextToken();
                //verifica se a varuável já foi declarada 
                if (symbolTable.getInGlobal(name) != null) {
                    error.show("Variavel " + name + " ja foi declarada");
                }


                if (isBoolean == true) {
                    v = new VarDec(name, Type.booleanType);
                } else {
                    v = new VarDec(name, Type.integerType);
                }

                symbolTable.putInGlobal(name, v);
                globalVarList.addElement(v);


                // se for diferente de "," significa que nao existem mais variaveis 
                if (lexer.token != Symbol.COMMA) {

                    lexer.nextToken();
                    break;
                }

                // se for "," significa que existem mais variaveis declaradas 
                // na mesma linha de um determinado tipo                
                lexer.nextToken();

            }


        }
        return globalVarList;
    }

   //Lista de variaveis locais
    private LocalVarList localVar() {

        LocalVarList localVarList = new LocalVarList();

        while (lexer.token == Symbol.INTEGER || lexer.token == Symbol.BOOLEAN) {
            boolean isBoolean = false;
            VarDec v;

            // flag de identificacao de tipo de variavel
            if (lexer.token == Symbol.BOOLEAN) {
                isBoolean = true;
            }

            lexer.nextToken();

            //estamos no nome da variavel
            while (true) {
                if (lexer.token != Symbol.IDENT) {
                    error.signal("Esperado Identificador");
                    // name of the identifier
                }
                String name = (String) lexer.getStringValue();
                lexer.nextToken();
                //Verifica se já foi declarada
                if (symbolTable.getInLocal(name) != null) {
                    error.show("Variavel " + name + " ja foi declarada");
                }


                if (isBoolean == true) {
                    v = new VarDec(name, Type.booleanType);
                } else {
                    v = new VarDec(name, Type.integerType);
                }

                symbolTable.putInLocal(name, v);
                localVarList.addElement(v);


                // se for diferente de "," significa que nao existem mais variaveis 
                if (lexer.token != Symbol.COMMA) {

                    lexer.nextToken();
                    break;
                }

                // se for "," significa que existem mais variaveis declaradas 
                // na mesma linda de um determinado tipo                
                lexer.nextToken();

            }


        }
        return localVarList;
       
        
    }
       
    
   
    private Subroutine procDec() {
        // ProcDec ::= "proc" [ Type ] Id "(" [ ParamList ] ")" [ VarDec { VarDec } ] ProcBody              

        lexer.nextToken();
        boolean isProc = true;
        boolean isBoolean = true;
       
        if (lexer.token == Symbol.INTEGER || lexer.token == Symbol.BOOLEAN) {
            // flag de identificacao de tipo
            if (lexer.token != Symbol.BOOLEAN) {
                isBoolean = false;
                
            }
            isProc = false;

            lexer.nextToken();
        }

        if (lexer.token != Symbol.IDENT) {
            error.signal("Esperado Identificador");
        }
        String name = (String) lexer.getStringValue();
               
        // verificacao de subrotina declarada com mesmo nome de variavel global
        // ou de subrotina declarada com mesmo nome de outra subrotina (proc/func)
        Object obj = symbolTable.getInGlobal(name);
        Subroutine s = null;
                
        if (obj instanceof Subroutine) {
            s = (Subroutine) symbolTable.getInGlobal(name);
            //Verifica se já foi declarado
            if (s != null) {
                error.signal("Subrotina " + name + " ja foi declarada");
            }
        } else {
            VarDec v = (VarDec) symbolTable.getInGlobal(name);
            if (v != null) {
                error.signal("Ja existe uma variavel global " + name + ", portanto, nao se pode declarar uma subrotina com o mesmo nome");
            }
        }

        
        
        
        
        lexer.nextToken();

        if (isProc == false) {
            
            if (isBoolean == true) {
                s = currentFunction = new Procedure(name, Type.booleanType);
                currentProcedure = null;
            } else {
                s = currentFunction = new Procedure(name, Type.integerType);
                currentProcedure = null;
            }
            
        } else {
            
            // entao eh procedimento
            s = new Procedure(name);
            currentFunction = null;
            currentProcedure = (Procedure) s;
        }
       
       // insere s na symbol table
       symbolTable.putInGlobal(name, s);
        
       if ( lexer.token != Symbol.LEFTPAR ) {
         error.show("( esperadp");
         lexer.skipBraces();
       }
       else{
         lexer.nextToken();
       }
       
       if ( lexer.token != Symbol.RIGHTPAR){ 
            s.setParamList( paramList() );
            //error.show("proceumentos main must be a parameterless procedure");
       }
                            
       if ( lexer.token != Symbol.RIGHTPAR ) {
         error.show(") esperado");
         lexer.skipBraces();
       }
       else{
         lexer.nextToken();
       }
       
       
       if ( lexer.token == Symbol.INTEGER || lexer.token == Symbol.BOOLEAN ) {
         s.setLocalVarList( localVar() );
       }
       
       s.setCompositeStatement( compositeCommand() );
       
       
       symbolTable.removeLocalIdent();
       return s;
    }
         
        
    
   
    private ParamList paramList() {
        //ParamList ::= Type Id {"," Type Id }
        
        boolean isBoolean = true;
        ParamList paramList = new ParamList();;
        
        while (true) {
            if (lexer.token != Symbol.INTEGER && lexer.token != Symbol.BOOLEAN) {
                error.show("Tipo  esperado na paramList");
                
            } else {

                if (lexer.token != Symbol.BOOLEAN) {
                    isBoolean = false;
                }

                lexer.nextToken();

                if (lexer.token != Symbol.IDENT) {
                    error.signal("Identificador esperado");
                }
                // nome do identificador
                String name = (String) lexer.getStringValue();
                lexer.nextToken();
                
                if (symbolTable.getInLocal(name) != null) {
                    error.show("Parametro " + name + " ja foi declarado");
                }
                
                VarDec v;

                if (isBoolean == true) {
                    v = new VarDec(name, Type.booleanType);
                } else {
                    v = new VarDec(name, Type.integerType);
                }
                //Insere na tabela local
                symbolTable.putInLocal(name, v);
                paramList.addElement(v);
                
                if (lexer.token != Symbol.COMMA) {
                    return paramList;
                } else {
                    lexer.nextToken();
                }


            }


        }
    }

    
    private CompositeCommand compositeCommand() {
        // CompositeCommand ::= "begin" { Command } "end"       
        // Command ::= PrintCommand | AssignmentCommand | WhileCommand | ForCommand 
        //                          | IfCommand | CompositeCommand | ReturnCommand | ProcCall


        if (lexer.token != Symbol.BEGIN) {
            error.show("begin esperado");
        } else {
            lexer.nextToken();
        }
        ArrayList<Command> cl = commandList();        
        
        if (lexer.token != Symbol.END) {
            error.show("end esperado");
        } else {
            lexer.nextToken();
        }

        return new CompositeCommand(cl);
    }

    
    private ArrayList<Command> commandList() {

        int tk;
        Command aCommand;
        ArrayList<Command> v = new ArrayList<Command>();

        while ((tk = lexer.token) != Symbol.END && tk != Symbol.ELSE) {
            aCommand = null;
            try {
                
                aCommand = command();
            } catch (CommandException e) {
                lexer.skipToNextStatement();
            }
            if (aCommand != null) {
                v.add(aCommand);
                
                if (lexer.token != Symbol.SEMICOLON) {
                    error.show("; esperado", true);
                    lexer.skipPunctuation();
                } else {
                    lexer.nextToken();
                }
            }
        }

        return v;
    }
    
    
   private Command command() throws CommandException {
        // Command ::= PrintCommand | AssignmentCommand | WhileCommand | ForCommand 
        //                          | IfCommand | CompositeCommand | ReturnCommand | ProcCall


        switch (lexer.token) {
            case Symbol.IDENT:
                //verifica se é Procedure
                if (symbolTable.get(lexer.getStringValue()) instanceof Procedure){                
                    return procedureCall();
                } else {
                    return assignmentCommand();
                }
            case Symbol.IF:
                return ifCommand();
            case Symbol.PRINT:
                return printCommand();
            case Symbol.FOR:
                return forCommand();
            case Symbol.WHILE:
                return whileCommand();
            case Symbol.BEGIN:
                return compositeCommand();
            case Symbol.RETURN:
                return returnCommand();
            default:
                error.show("Command esperado");
                throw new CommandException();
        }
    }
                
    
    private AssignmentCommand assignmentCommand() {
    //AssignmentCommand ::= Id "=" OrExpr ";"    
        VarDec v = checkVariable();
        //String name = v.getName();
          
        if ( lexer.token != Symbol.ASSIGN ) {
          error.show("= esperado");
          lexer.skipToNextStatement();
          return null;
        }
        else{
          lexer.nextToken();
        }
        Expr right = orExpr();
          //Verifica se expressão tem o mesmo tipo da variável, senão, acusa erro
        
        if ( v.getType() != right.getType() ){ 
          error.show("Erro de tipo na atribuição");
        }
        
        return new AssignmentCommand( v, right );
    }    
        
    
    private IfCommand ifCommand() {
        //IfCommand ::= "if" OrExpr "then" Command [ "else" Command ]
        lexer.nextToken();
        Expr e = orExpr();
          
          
        if ( e.getType() != Type.booleanType ){ 
          error.show("Tipo booleano esperado no comando if");
        }
        
        if ( lexer.token != Symbol.THEN ){ 
          error.show("then esperado");
        }else{
          lexer.nextToken();
        }
        ArrayList<Command> thenPart = commandList();
        ArrayList<Command> elsePart = null;
        if ( lexer.token == Symbol.ELSE ) {
            lexer.nextToken();
            elsePart = commandList();
        }
        
        return new IfCommand( e, thenPart, elsePart );
    }                                
    
   
    private PrintCommand printCommand() {
        //PrintCommand ::= "print" OrExpr ";"    
        lexer.nextToken();

        Expr e = orExpr();
      
        return new PrintCommand(e);
    }

    private Command forCommand() throws CommandException {
        //ForCommand ::= "for" Id "=" OrExpr "to" OrExpr "do" Command    
        VarDec v = null;

        lexer.nextToken();
        if (lexer.token != Symbol.IDENT) {
            error.signal("Variavel esperada");
        }
        v = checkVariable();
       
        if (lexer.token != Symbol.ASSIGN) {
            error.show("= esperado");
        } else {
            lexer.nextToken();
        }
        Expr exprLower = orExpr();
        if (lexer.token != Symbol.TO) {
            error.show("to esperado");
        } else {
            lexer.nextToken();
        }
        Expr exprUpper = orExpr();
        // Análise semnatica, verifica os tipos
        if (exprLower.getType() != exprUpper.getType()) {
            error.show("Ambas as expressões devem possuir o mesmo tipo");
        }
        if (lexer.token != Symbol.DO) {
            error.show("do esperado");
        } else {
            lexer.nextToken();
        }
        return new ForCommand(v, exprLower, exprUpper, command());
    }

    
    private Command whileCommand() throws CommandException {
    //WhileCommand ::= "while" OrExpr "do" Command
        lexer.nextToken();
        Expr expr = orExpr();
        if ( expr.getType() != Type.booleanType ){
          error.show("Expressão booleano esperada");
        }
        if ( lexer.token != Symbol.DO ){
          error.show("do esperado");
        }else{
          lexer.nextToken();
        }
        return new WhileCommand(expr, command() );
    }
    
  
    private ReturnCommand returnCommand() {
        //    ReturnCommand ::= "return" OrExpr ";"
        lexer.nextToken();
        Expr e = orExpr();
        
        if (currentFunction == null) {
            error.show("return dentro de uma procedure, return só existe em função");
        } else {
            if (currentFunction.getReturnType() != e.getType()) {
                error.show("Tipo de retorno não combina com o tipo da função");
            }
        }
        return new ReturnCommand(e);
    }

    
    
    private ProcedureCall procedureCall() {
        //  ProcCall ::= Id "(" [ OrExpr { "," OrExpr } ] ")" ";"

       
        ExprList anExprList = null;

        String name = (String) lexer.getStringValue();
        
        
        lexer.nextToken();
        Procedure p = (Procedure) symbolTable.getInGlobal(name);
                        
        if (lexer.token != Symbol.LEFTPAR) {
            error.show("( esperado");
            lexer.skipBraces();
        } else {
            lexer.nextToken();
        }

        if (lexer.token != Symbol.RIGHTPAR) {
            
            anExprList = exprList(p.getParamList());
            if (lexer.token != Symbol.RIGHTPAR) {
                error.show("Erro na expressão");
            } else {
                lexer.nextToken();
            }
        } else {
            //verifica de possui parametro
            if (p.getParamList() != null && p.getParamList().getSize() != 0) {
                error.signal("Parametro esperado");
            }
            lexer.nextToken();
        }

        return new ProcedureCall(p, anExprList);
    }


    private ExprList exprList( ParamList paramList )
    {
       ExprList anExprList;
       boolean firstErrorMessage = true;
       
       if ( lexer.token == Symbol.RIGHTPAR ) 
          return null;
       else {
          
          VarDec parameter; 
          int sizeParamList = paramList.getSize();
          
          anExprList = new ExprList();
          
          int i =0;
          
          while ( true ) {
              
              
              parameter = paramList.getParamList().get(i);
              
              
            if ( sizeParamList < 1 && firstErrorMessage ) {
              error.show("Numero errado de parametros na chamada");
              firstErrorMessage = false;
            }
            sizeParamList--;
            Expr anExpr = orExpr();
            
            
            if ( parameter.getType() != anExpr.getType()){
              error.show("Erro de tipo na combinação de parametro");
            }
            
            anExprList.addElement( anExpr );
            if ( lexer.token == Symbol.COMMA ) 
              lexer.nextToken();
            else
              break;
            
            
            i++;
          }
           
          if ( sizeParamList > 0 && firstErrorMessage ) {
            error.show("Numero errado de parametros");
          }
          return anExprList;
       }
    }

    
    
    private VarDec checkVariable() {
        
        
        VarDec v = null;
        
        String name = (String ) lexer.getStringValue();
        try { 
          v = (VarDec ) symbolTable.getInLocal( name );
        } catch ( Exception e ) {
        }
               
        if ( v == null ) {
            
            //checa a variável a nível global
            v = (VarDec ) symbolTable.getInGlobal( name );
            if ( v == null ) {
                error.show("Variavel " + name + " não foi declarada");
            }
            
            symbolTable.putInLocal( name, v );
        }
        lexer.nextToken();
        return v;
    }

    
    
    
    private Expr orExpr() {
        //  OrExpr ::= AndExpr [ "or" AndExpr ]

        Expr left, right;
        left = andExpr();
        if (lexer.token == Symbol.OR) {
            lexer.nextToken();
            right = andExpr();
            
            if (left.getType() != Type.booleanType && right.getType() != Type.booleanType) {
                error.show("Expressão de tipo booleano esperada");
            }
            left = new CompositeExpr(left, Symbol.OR, right);
        }
        return left;
    }
   
    
    private Expr andExpr() {
        //  AndExpr ::= RelExpr [ "and" RelExpr ]

        Expr left, right;
        left = relExpr();
        if (lexer.token == Symbol.AND) {
            lexer.nextToken();
            right = relExpr();
            
            if (left.getType() != Type.booleanType && right.getType() != Type.booleanType) {
                error.show("Expressão de tipo booleano esperada");
            }
            left = new CompositeExpr(left, Symbol.AND, right);
        }
        return left;
    }


    private Expr relExpr() {
        //  RelExpr ::= AddExpr [ RelOp AddExpr ]

        Expr left, right;
        left = addExpr();
        int op = lexer.token;
        if (op == Symbol.EQ || op == Symbol.NEQ || op == Symbol.LE || op == Symbol.LT
                || op == Symbol.GE || op == Symbol.GT) {
            lexer.nextToken();
            right = addExpr();
         
            if (left.getType() != right.getType()) {
                error.show("Erro de tipo na expressão");
            }
            left = new CompositeExpr(left, op, right);
        }
        return left;
    }
          

    private Expr addExpr() {
        //  AddExpr ::= MultExpr { AddOp MultExpr }

        int op;
        Expr left, right;
        left = multExpr();
        while ((op = lexer.token) == Symbol.PLUS
                || op == Symbol.MINUS) {
            lexer.nextToken();
            right = multExpr();
           
            if ( left.getType() != Type.integerType || right.getType() != Type.integerType){
                error.show("Expressão do tipo inteiro esperada");
            }
            left = new CompositeExpr(left, op, right);
        }
        return left;
    }
           

    //ACABADO
    private Expr multExpr() {
        //MultExpr ::= SimpleExpr { MultOp SimpleExpr }

        Expr left, right;
        left = simpleExpr();
        int op;
        while ((op = lexer.token) == Symbol.MULT || op == Symbol.DIV || op == Symbol.REMAINDER) {
            lexer.nextToken();
            right = simpleExpr();
          
            if (left.getType() != Type.integerType || right.getType() != Type.integerType) {
                error.show("Expressão do tipo inteiro esperada");
            }
            left = new CompositeExpr(left, op, right);
        }
        return left;
    }
           
    private Expr simpleExpr() {
        /*
        * SimpleExpr ::= Number | "true" | "false" | ’(’ OrExpr ’)’ | "not" 
        SimpleExpr | AddOp SimpleExpr | Id | getInteger | FuncCall
        */

        Expr e;

        // verifica qual chamada será feita
        switch (lexer.token) {
            case Symbol.NUMBER:
                return number();
            case Symbol.TRUE:
                lexer.nextToken();
                return BooleanExpr.True;
            case Symbol.FALSE:
                lexer.nextToken();
                return BooleanExpr.False;
            case Symbol.LEFTPAR:
                lexer.nextToken();
                e = orExpr();
                if (lexer.token != Symbol.RIGHTPAR) {
                    error.show(") esperada");
                    lexer.skipBraces();
                } else {
                    lexer.nextToken();
                }
                return new ParenthesisExpr(e);
            case Symbol.NOT:
                lexer.nextToken();
                e = orExpr();
                if (e.getType() != Type.booleanType) {
                    error.show("Expressão do tipo booleana esperada");
                }
                return new UnaryExpr(e, Symbol.NOT);
            case Symbol.PLUS:
                lexer.nextToken();
                e = orExpr();
                
                if (e.getType() != Type.integerType) {
                    error.show("Expression of type integer expected");
                }
                return new UnaryExpr(e, Symbol.PLUS);
            case Symbol.MINUS:
                lexer.nextToken();
                e = orExpr();
             
                if (e.getType() != Type.integerType) {
                    error.show("Expressão do tipo inteiro esperada");
                }
                return new UnaryExpr(e, Symbol.MINUS);
              
            case Symbol.GETINTEGER:
                lexer.nextToken();
                return new GetIntegerExpr();

            default:
               
                if (lexer.token != Symbol.IDENT) {
                    error.show("Identificador esperado");
                    lexer.nextToken();
                    
                } else {
                    
                    String name = (String) lexer.getStringValue();
                    
                    Object objIdent = symbolTable.get(name);
                    if (objIdent == null) {
                        error.show("Identificador não foi delcarado");
                        lexer.nextToken();
                    }

                    if (objIdent instanceof Subroutine) {

                        if (((Subroutine) objIdent).getReturnType() == null) {
                            error.show("Identificador não é uma subrotina");
                           
                        } else {
                            //Chama função
                            e = functionCall();
                            return new UnaryExpr(e, Symbol.FUNCTION);
                            
                            
                        }
                    } else {
                        //é uam variavel
                        VarDec v = (VarDec) objIdent;
                        lexer.nextToken();
                        return new VariableExpr(v);
                    }
                }
                return null;
        }

    }

    
    private Expr functionCall() {
        //FuncCall ::= Id "(" [ OrExpr { "," OrExpr } ] ")"
        ExprList anExprList = null;

        String name = (String) lexer.getStringValue();
        lexer.nextToken();
        
        Procedure p = (Procedure) symbolTable.getInGlobal(name);
        if (p == null) {
            error.signal("Função não foi declarada!");
        } else {
            if (lexer.token != Symbol.LEFTPAR) {
                error.show("( esperado");
                lexer.skipBraces();
            } else {
                lexer.nextToken();
            }

            if (lexer.token != Symbol.RIGHTPAR) {
               
                anExprList = exprList(p.getParamList());
                if (lexer.token != Symbol.RIGHTPAR) {
                    error.show("Erro na expressão");
                } else {
                    lexer.nextToken();
                }
            } else {
                
                if (p.getParamList() != null && p.getParamList().getSize() != 0) {
                    error.show("Parametro esperado");
                }
                lexer.nextToken();
            }

        }
        return new FunctionCall(p, anExprList);

    }

    
    private NumberExpr number() {
        //Number ::= Digit { Digit }
        NumberExpr e = null;
        
        int value = lexer.getNumberValue();
        lexer.nextToken();
        return new NumberExpr(value);
    }    
    
    
    
}
